package org.eden.heartbeat.core;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eden.heartbeat.api.model.MachineInfo;
import org.eden.heartbeat.core.ping.PingService;
import org.eden.heartbeat.core.ping.PingServiceAdmin;
import org.eden.heartbeat.core.ping.PingServiceFactory;
import org.eden.heartbeat.core.report.ReportService;
import org.eden.heartbeat.core.report.ReportServiceFactory;

import java.text.MessageFormat;
import java.util.Date;

import static org.eden.heartbeat.core.configuration.CoreApplicationConfiguration.heartbeatIntervalOffline;
import static org.eden.heartbeat.core.configuration.CoreApplicationConfiguration.heartbeatIntervalOnline;

/**
 * Thread responsible for pinging a remote machine and registering its status.
 *
 * @author trsimoes
 * @version $Revision:$
 */
public class HeartbeatThread extends Thread {

    private static Log LOG = LogFactory.getLog(HeartbeatThread.class);

    private boolean run = true;

    private PingService pingService;

    private MachineInfo machineInfo;

    private ReportService reportService;

    public HeartbeatThread(MachineInfo machineInfo) {
        this.machineInfo = machineInfo;
        this.pingService = PingServiceFactory.getInstance().createNew(machineInfo);
        this.reportService = ReportServiceFactory.getInstance().getServiceInstance();
    }

    @Override
    public void run() {

        while (this.run) {

            // ping remote machine
            boolean result = this.pingService.ping();

            if (LOG.isDebugEnabled()) {
                LOG.debug(MessageFormat.format("[{0}] ping {1}", machineInfo.getDestinyInfo(),
                        result ? "succeeded" : "failed"));
            }

            // report result
            this.reportService.report(this.machineInfo, new Date(), result);

            // wait for next ping
            try {
                Thread.sleep(result ? heartbeatIntervalOnline : heartbeatIntervalOffline);
            } catch (InterruptedException e) {
                if (LOG.isErrorEnabled()) {
                    LOG.error("Error running HeartbeatThread", e);
                }
            }
        }
    }

    public void terminateExecution() {
        this.run = false;
    }

    public void reload(final MachineInfo machineInfo) {
        this.machineInfo = machineInfo;

        if (this.pingService instanceof PingServiceAdmin) {
            ((PingServiceAdmin) this.pingService).reloadConfigurations(this.machineInfo);
        } else {
            if (LOG.isWarnEnabled()) {
                LOG.warn("Configurations could not be reloaded.");
            }
        }
    }
}